package conf

import (
	"bytes"
	"crypto/md5"
	"crypto/rand"
	"encoding/base64"
	"encoding/binary"
	"encoding/hex"
	"encoding/json"
	"fmt"
	"github.com/spf13/cast"
	"io"
	"reflect"
	"strings"
	"sync"
	"time"
	"unsafe"
)
var (
	BuffPool = sync.Pool{
		New: func() interface{} {
			return bytes.NewBuffer([]byte{})
		},
	}
)
type Basic struct {
	sync.RWMutex
	Isdirty bool
}
type Safe struct {
	Basic
	Next map[interface{}]*Safe
}

func (self *Safe) GetSafe(arg ...interface{}) (cur *Safe) {
	cur = self
	for _, value := range arg {
		if len(cur.Next) == 0 {
			cur.Next = map[interface{}]*Safe{}
		}
		if cur.Next[value] == nil {
			cur.Next[value] = &Safe{}
		}
		cur = cur.Next[value]
	}
	return
}

//-------------------------------------------------------------------------------
func NewStructPtrAndNext(dst interface{}) {
	dv := reflect.ValueOf(dst)
	k := dv.Kind()
	if k != reflect.Ptr {
		return
	}
	if dv.IsNil() { //指针地址为空
		return
	}

	dv = dv.Elem()
	if !dv.IsNil() { //指针不为空
		return
	}
	elemType := dv.Type().Elem()
	k = elemType.Kind()
	switch k {
	case reflect.Ptr:
		elemType = elemType.Elem()
	case reflect.Map:
	}
	ev := reflect.New(elemType)
	if !dv.CanSet() {
		return
	}
	dv.Set(ev)
	UpdateStructNext(ev, true, true)
}

//补全或重置结构成员,成员小写不能赋值
func InitStructNext(input interface{}, reset, next bool) {
	//fmt.Print(Callstack())
	getValue := reflect.ValueOf(input)
	kind := getValue.Kind()
	switch kind {
	case reflect.Map:
		if getValue.IsNil() || reset {
			d := reflect.ValueOf(&input).Elem()
			getType := getValue.Type()
			if !d.CanSet() {
				return
			}
			d.Set(reflect.MakeMap(getType))
		}
	case reflect.Slice:
		if reset {
			d := reflect.ValueOf(&input).Elem()
			getType := getValue.Type()
			if !d.CanSet() {
				return
			}
			d.Set(reflect.MakeSlice(getType, 0, 0))
		}
	case reflect.Struct:
	default:
		UpdateStructNext(getValue, reset, next)
	}
}

//reset强制重置 next:下级初始化
func UpdateStructNext(ev reflect.Value, reset bool, next bool) {
	kind1 := ev.Kind()
	switch kind1 {
	case reflect.String:
		if reset && ev.CanSet() {
			ev.SetString("")
		}
	case reflect.Int, reflect.Int8, reflect.Int16, reflect.Int32, reflect.Int64:
		if reset && ev.CanSet() {
			ev.SetInt(0)
		}
	case reflect.Uint, reflect.Uint8, reflect.Uint16, reflect.Uint32, reflect.Uint64:
		if reset && ev.CanSet() {
			ev.SetUint(0)
		}
	case reflect.Float64, reflect.Float32:
		if reset && ev.CanSet() {
			ev.SetFloat(0)
		}
	case reflect.Bool:
		if reset && ev.CanSet() {
			ev.SetBool(false)
		}
	case reflect.Ptr:
		for i := 0; i < ev.Elem().Type().NumField(); i++ {
			value := ev.Elem().Field(i)
			kind := value.Kind()
			if !value.CanSet() {
				continue
			}
			switch kind {
			case reflect.Ptr:
				if next && (reset || value.IsNil()) {
					new := reflect.New(value.Type().Elem())
					value.Set(new)
					value = value.Elem()
					//下下级初始化
					UpdateStructNext(new, reset, next)
				}
			case reflect.Map:
				if reset || value.IsNil() {
					value.Set(reflect.MakeMap(value.Type()))
				}
			case reflect.Slice:
				if reset {
					value.Set(reflect.MakeSlice(value.Type(), 0, 0))
				}
			case reflect.String:
				if reset {
					value.SetString("")
				}
			case reflect.Int, reflect.Int8, reflect.Int16, reflect.Int32, reflect.Int64:
				if reset {
					value.SetInt(0)
				}
			case reflect.Uint, reflect.Uint8, reflect.Uint16, reflect.Uint32, reflect.Uint64:
				if reset {
					value.SetUint(0)
				}
			case reflect.Float64, reflect.Float32:
				if reset {
					value.SetFloat(0)
				}
			case reflect.Bool:
				if reset {
					value.SetBool(false)
				}
			default:
			}
		}
	default:
	}
}

//初始化切片大小,传入指针地址
func InitSliceSize(dst interface{}, size int) {
	dv := reflect.ValueOf(dst)
	k := dv.Kind()
	if k != reflect.Ptr {
		return
	}
	if dv.IsNil() {
		return
	}
	dv = dv.Elem()
	elemType := dv.Type().Elem()
	k = elemType.Kind()
	if k == reflect.Ptr {
		elemType = elemType.Elem()
	}
	for i := 1; i <= size; i++ {
		ev := reflect.New(elemType)
		if k != reflect.Ptr {
			ev = ev.Elem()
		}
		dv.Set(reflect.Append(dv, ev))
	}
}

//-------------------------------------------------------------------------------
func ToBool(i interface{}) bool {
	return cast.ToBool(i)
}
func ToTime(i interface{}) time.Time {
	return cast.ToTime(i)
}
func ToDuration(i interface{}) time.Duration {
	return cast.ToDuration(i)
}
func ToStringMap(i interface{}) map[string]interface{} {
	return cast.ToStringMap(i)
}
func ToSlice(i interface{}) []interface{} {
	return cast.ToSlice(i)
}
func ToStringSlice(i interface{}) (ret []string) {
	ret=[]string{}
	for _, value := range cast.ToSlice(i) {
			ret=append(ret,ToString(value))
	}
	return
}
func ToInt32(i interface{}) int32 {
	return cast.ToInt32(i)
}
func ToInt64(i interface{}) int64 {
	return cast.ToInt64(i)
}
func ToFloat64(i interface{}) float64 {
	return cast.ToFloat64(i)
}
func ToString(i interface{}) string {
	return cast.ToString(i)
}
func ToStringMapString(i interface{}) map[string]string {
	t,_:=json.Marshal(i)
	return cast.ToStringMapString(string(t))
}
func ToBytes(in interface{}) []byte {
	if v, ok := in.(string); ok {
		return []byte(v)
	}
	buf := BuffPool.Get().(*bytes.Buffer)
	if err := binary.Write(buf, binary.BigEndian, in); nil != err {
		fmt.Errorf("write error: %s", err.Error())
	}
	data := make([]byte, buf.Len())
	copy(data, buf.Bytes())
	buf.Reset()
	BuffPool.Put(buf)
	return data
}
func CopyUint64Slice(input []uint64) []uint64 {
	output := make([]uint64, len(input))
	copy(output, input)
	return output
}
func CopyUint64Map(in map[uint64]uint64) map[uint64]uint64 {
	ret := make(map[uint64]uint64, len(in))
	for k, v := range in {
		ret[k] = v
	}
	return ret
}

func GetMd5String(s string) string {
	h := md5.New()
	h.Write([]byte(s))
	return hex.EncodeToString(h.Sum(nil))
}
func GenGuid() string {
	b := make([]byte, 48)
	if _, err := io.ReadFull(rand.Reader, b); err != nil {
		return ""
	}
	return GetMd5String(base64.URLEncoding.EncodeToString(b))
}

func Base64Decode(in string) string {
	tmp, _ := base64.StdEncoding.DecodeString(in)
	return string(tmp)
}

func Base64Encode(in string) string {
	return base64.StdEncoding.EncodeToString([]byte(in))
}

func IsSliceContant(slice []interface{}, value interface{}) bool {
	for _, v := range slice {
		if v == value {
			return true
		}
	}
	return false
}

func ComputeSlice(slice []interface{}) int64 {
	var ret int64
	for _, v := range slice {
		ret += v.(int64)
	}
	return ret
}

func BitIsSet(value uint32, position uint32) bool {
	if 32 < position {
		return false
	}

	return 0 != value&uint32(0x01<<position)
}

func SetBit(value *uint32, position uint32) {
	if 32 > position {
		*value |= uint32(0x01 << position)
	}
}

func ResetBit(value *uint32, position uint32) {
	if 32 > position {
		*value &= ^uint32(0x01 << position)
	}
}

func AddToSlice(slice []interface{}, value interface{}) {
	var find = false
	for _, v := range slice {
		if v == value {
			find = true
			break
		}
	}
	if !find {
		slice = append(slice, value)
	}
}

func DeleteToSlice(slice []interface{}, value interface{}) {
	for k, v := range slice {
		if v == value {
			slice = append(slice[:k], slice[k+1:]...)
			break
		}
	}
}

/**
@brief 雕像加成key-value array转换为map
*/
func StatueFuncArrayToMap(keys []string, values []uint32) map[string]uint32 {
	if nil == keys || 0 == len(keys) || nil == values || 0 == len(values) {
		return nil
	}
	arr := make(map[string]uint32)
	for i := 0; i < len(keys); i++ {
		arr[keys[i]] = values[i]
	}
	return arr
}

func DelNum(a, b int32) int32 {
	if a > b {
		return a - b
	} else {
		return 0
	}
}
func Max(a, b int32) int32 {
	if a > b {
		return a
	} else {
		return b
	}
}
func Min(a, b int32) int32 {
	if a > b {
		return b
	} else {
		return a
	}
}
func MemSet(s unsafe.Pointer, c byte, n uintptr) {
	ptr := uintptr(s)
	var i uintptr
	for i = 0; i < n; i++ {
		pByte := (*byte)(unsafe.Pointer(ptr + i))
		*pByte = c
	}
}
func InSlice(slice interface{}, value interface{}) bool {
	switch t := slice.(type) {
	case []string:
		for _, v := range t {
			if v == ToString(value) {
				return true
			}
		}
	}
	return false
}


func Link(args ...interface{}) (ret string) {
	in := []string{}
	for _, v := range args {
		in = append(in, ToString(v))
	}
	return strings.Join(in, ".")
}
func UnLink(d string) (ret []string) {
	return strings.Split(d,".")
}


func Segment(p1x, p1y, p2x, p2y, p3x, p3y, p4x, p4y int32) bool { //判断线段p1-p2 p3--p4是否相交
	if Max(p1x, p2x) >= Min(p3x, p4x) && Max(p3x, p4x) >= Min(p1x, p2x) &&
		Max(p1y, p2y) >= Min(p3y, p4y) && Max(p3y, p4y) >= Min(p1y, p2y) { //交叉或斜平行
		if Cross(p1x, p1y, p2x, p2y, p3x, p3y)*Cross(p1x, p1y, p2x, p2y, p4x, p4y) <= 0 &&
			Cross(p3x, p3y, p4x, p4y, p1x, p1y)*Cross(p3x, p3y, p4x, p4y, p2x, p2y) <= 0 {
			return true
		}
	}
	return false
}
func Cross(p1x, p1y, p2x, p2y, p3x, p3y int32) int32 { //判断点p3在直线p1-p1的左边还是右边
	x1 := p2x - p1x
	y1 := p2y - p1y
	x2 := p3x - p1x
	y2 := p3y - p1y
	return x1*y2 - x2*y1

}